package org.example.Proxy;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;

import java.net.InetSocketAddress;

// 自定义的HTTP处理器，继承自SimpleChannelInboundHandler，用于处理FullHttpRequest
public class CustomHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    // 创建一个新的Bootstrap实例，用于连接到目标服务器
    private final Bootstrap bootstrap = new Bootstrap();
    // 用于与目标服务器通信的出站Channel
    private Channel outboundChannel;
    // 目标服务器的地址和端口
    private static final String TARGET_HOST = "localhost";
    private static final int TARGET_PORT = 3000;
    private ChannelHandlerContext innerCtx;

    // 构造函数，初始化Bootstrap和相关的处理器
    public CustomHttpHandler() {
        // 创建一个新的NioEventLoopGroup，用于处理与目标服务器的连接
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        bootstrap.group(workerGroup)
                .channel(NioSocketChannel.class) // 使用NioSocketChannel来建立连接
                .handler(new ChannelInitializer<Channel>() { // 设置出站Channel的处理器
                    @Override
                    protected void initChannel(Channel ch) {
                        ch.pipeline().addLast(new HttpRequestEncoder()); // 编码HTTP请求
                        ch.pipeline().addLast(new HttpResponseDecoder()); // 解码HTTP响应
                        // 添加自定义的转发处理器，用于处理从目标服务器接收到的响应
                        ch.pipeline().addLast(new ForwardingHandler(CustomHttpHandler.this));
                    }
                });
    }

    // 重写channelRead0方法，处理接收到的FullHttpRequest
    @Override
    protected void channelRead0(final ChannelHandlerContext ctx, FullHttpRequest request) {
        innerCtx = ctx;
        // 假设我们要代理除了"/special-path"以外的所有请求
        if ("/special-path".equals(request.uri())) {
            // 对于特定路径"/special-path"的请求，可以在这里进行特殊处理
            // ...
        } else {
            // 对于其他请求，我们将其转发到目标服务器
            // 移除原始请求的Host头部，因为我们可能会发送到不同的服务器
            request.headers().remove(HttpHeaderNames.HOST);
            // 添加新的Host头部，指向目标服务器
            request.headers().add(HttpHeaderNames.HOST, TARGET_HOST);

            // 创建一个请求的副本，因为Netty的HttpRequest是不可变的
            final FullHttpRequest modifiedRequest = request.copy();

            // 连接到目标服务器
            ChannelFuture future = bootstrap.connect(new InetSocketAddress(TARGET_HOST, TARGET_PORT));
            outboundChannel = future.channel();
            future.addListener((ChannelFutureListener) future1 -> {
                if (future1.isSuccess()) {
                    // 如果连接成功，将修改后的请求发送到目标服务器
                    outboundChannel.writeAndFlush(modifiedRequest).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    // 如果连接失败，关闭当前的ChannelHandlerContext
                    ctx.close();
                }
            });
        }
    }

    // 异常处理方法
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    // 内部类，用于处理从目标服务器接收到的响应，并将其转发回客户端
    class ForwardingHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
        private final Channel inboundChannel;

        ForwardingHandler(CustomHttpHandler handler) {
            // 传入当前处理器所在的ChannelHandlerContext的Channel，即客户端的连接
            inboundChannel = handler.innerCtx.channel();
        }

        // 重写channelRead0方法，处理从目标服务器接收到的FullHttpResponse
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) {
            // 将响应转发回客户端，并添加监听器以便在写入失败时关闭连接
            inboundChannel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
        }

        // 异常处理方法
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
}